/**********************************************************************
 Copyright (C) 2009 Jaakko Vuori

 This file is part of FlexiWorker.
 For more information, see <http://code.google.com/p/flexi-worker/>

 FlexiWorker is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 FlexiWorker is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with FlexiWorker.  If not, see <http://www.gnu.org/licenses/>.
 **********************************************************************/

#include "timelinewidget.h"
#include <QtGui>
#include <QPainter>
#include <QDebug>
#include <QString>

TimeLineWidget::TimeLineWidget(QWidget* parent) : QWidget(parent), m_resizeFSM(*this)
{
    m_fontHeight = QFontMetrics(m_font).height();
    m_highlightedPresenceTime = -1;
    setMouseTracking(true);
}

void TimeLineWidget::setPresenceTimes(QList<TimeFrame> presenceTimes)
{
    m_presenceTimes = presenceTimes;
}


void TimeLineWidget::setWorkingTimes(QList<TimeFrame> workingTimes)
{
    m_workTimes = workingTimes;
    repaint();
}

void TimeLineWidget::setDayStartTime(QDateTime dayStartTime)
{
    m_dayStartTime = dayStartTime;
    QString str;
    str.sprintf("%d:%.2d", m_dayStartTime.time().hour(), m_dayStartTime.time().minute());

    m_zeroWidth = QFontMetrics(m_font).width(str);
    repaint();
}

int TimeLineWidget::highlightedWorkingTime() const
{
    return m_highlightedWorkingTime;
}

QDateTime TimeLineWidget::dayStartTime() const
{
    return m_dayStartTime;
}

void TimeLineWidget::paintEvent(QPaintEvent* /*event*/)
{
    QPainter painter(this);
    painter.save();

    for (int i = 0; i < m_workTimes.count(); ++i)
    {
        TimeFrame& w = m_workTimes[i];
        if (m_highlightedWorkingTime == i)
        {
            painter.setBrush(QBrush(QColor("darkgreen")));
        }
        else
        {
            painter.setBrush(QBrush(QColor("green")));
        }
        painter.setPen(QPen(QColor("black")));
        qreal leftPos = timeToPos(w.m_startTime);
        qreal rectWidth = timeToPos(w.m_endTime) - leftPos;
        painter.drawRect(QRectF(leftPos, 0, rectWidth, height() - m_fontHeight));
    }

    for (int i = 0; i < m_presenceTimes.count(); ++i)
    {
        TimeFrame& entry = m_presenceTimes[i];
        if (m_highlightedPresenceTime == i)
        {
            painter.setBrush(QBrush(QColor("darkred")));
            painter.setPen(QPen(QColor("darkred")));
        }
        else
        {
            painter.setBrush(QBrush(QColor("red")));
            painter.setPen(QPen(QColor("red")));
        }
        if (!entry.m_startTime.time().isNull() && !entry.m_endTime.time().isNull())
        {
            qreal leftPos = timeToPos(entry.m_startTime);
            qreal rectWidth = timeToPos(entry.m_endTime) - leftPos;
            painter.drawRect(QRectF(leftPos, (height() - m_fontHeight) / 4.0, rectWidth, (height() - m_fontHeight) / 2.0));
        }
        else
        {
            qreal pos = 0;
            if (!entry.m_startTime.isNull())
            {
                pos = timeToPos(entry.m_startTime);
            }
            else
            {
                pos = timeToPos(entry.m_endTime);
            }
            painter.drawEllipse(QPointF(pos, (height() - m_fontHeight) / 2), m_fontHeight / 4, m_fontHeight / 4);
            //qDebug() << "NULL time" << entry.m_startTime << entry.m_endTime;
        }
    }
    painter.restore();

    qreal timeLineWidth = width() - m_zeroWidth;
    qreal hourStep = timeLineWidth / 24.0;

    for (int i = 0; i < 24; ++i)
    {
        painter.drawLine(QLineF(i * hourStep + m_zeroWidth / 2, 0, i * hourStep + m_zeroWidth / 2, height() - m_fontHeight));
        painter.drawLine(QLineF(i * hourStep + hourStep / 2.0 + m_zeroWidth / 2, (height() - m_fontHeight) / 3.0, i * hourStep + hourStep / 2.0 + m_zeroWidth / 2, height() - m_fontHeight- (height() - m_fontHeight) / 3.0));
        painter.drawLine(QLineF(i * hourStep + hourStep / 4.0 + m_zeroWidth / 2, (height() - m_fontHeight) / 2.2, i * hourStep + hourStep / 4.0 + m_zeroWidth / 2, height() - m_fontHeight- (height() - m_fontHeight) / 2.2));
        painter.drawLine(QLineF((i + 1) * hourStep - hourStep / 4.0 + m_zeroWidth / 2, (height() - m_fontHeight) / 2.2, (i + 1) * hourStep - hourStep / 4.0 + m_zeroWidth / 2, height() - m_fontHeight - (height() - m_fontHeight) / 2.2));
    }
    painter.drawLine(QLineF(24 * hourStep + m_zeroWidth / 2, 0, 24 * hourStep + m_zeroWidth / 2, height() - m_fontHeight));


    for (int i = 0; i < 25; ++i)
    {
        QDateTime t = m_dayStartTime.addSecs(60 * 60 * i);
        QString str;
        str.sprintf("%d:%.2d", t.time().hour(), t.time().minute());
        int textWidth = QFontMetrics(m_font).width(str);
        painter.drawText(i * hourStep - textWidth / 2.0 + m_zeroWidth / 2, height(), str);
    }
}

qreal TimeLineWidget::timeToPos(const QDateTime& time)
{
    qreal timeLineWidth = width() - m_zeroWidth;
    return m_dayStartTime.secsTo(time) / qreal(60 * 60 * 24) * timeLineWidth + m_zeroWidth / 2;
}

QDateTime TimeLineWidget::posToTime(qreal position)
{
    qreal timeLineWidth = width() - m_zeroWidth;
    return m_dayStartTime.addSecs((60 * 60 * 24) / timeLineWidth * (position - m_zeroWidth / 2));
}

void TimeLineWidget::mouseMoveEvent(QMouseEvent* event)
{
    for (int i = 0; i < m_workTimes.count(); ++i)
    {
        TimeFrame& w = m_workTimes[i];
        qreal startPos = timeToPos(w.m_startTime);
        qreal endPos = timeToPos(w.m_endTime);

        //Cursor
        if ((event->posF().y() <= height() - m_fontHeight) &&
            (fabs(startPos - event->posF().x()) < 3 || fabs(endPos - event->posF().x()) < 3))
        {
            m_highlightedWorkingTime = i;
            repaint();
            m_resizeFSM.nearToEnd();
            setCursor(Qt::SizeHorCursor);
        }
        else
        {
            m_resizeFSM.farFromEnd();
            setCursor(Qt::ArrowCursor);
        }

        //Highlighting
        if (startPos <= event->posF().x() &&
            event->posF().x() <= endPos &&
            (event->posF().y() <= height() - m_fontHeight))
        {
            //w.setHighlight(true);
            m_highlightedWorkingTime = i;
            repaint();
        }


    }

    m_resizeFSM.mouseMoved();

/*
    foreach (TimeFrame e, m_entries)
    {
        qreal startPos = timeToPos(e.m_startTime.time());
        qreal endPos = timeToPos(e.m_endTime.time());

        if (event->pos().x() >= startPos && event->pos().x() <= endPos)
        {
            QPoint tipPos(mapToGlobal(QPoint(startPos, height() / 2 - m_fontHeight)));
            QToolTip::showText(tipPos, e.m_startTime.time().toString() + " - " + e.m_endTime.time().toString());
            return;
        }
    }
    QToolTip::hideText();
*/
}

void TimeLineWidget::leaveEvent(QEvent* /*event*/)
{
    m_highlightedWorkingTime = -1;
    m_highlightedPresenceTime = -1;
    repaint();
}

void TimeLineWidget::mousePressEvent(QMouseEvent* event)
{
    if (event->button() == 1 && m_highlightedWorkingTime >= 0)
    {
        TimeFrame& w = m_workTimes[m_highlightedWorkingTime];
        qreal startPos = timeToPos(w.m_startTime);
        qreal endPos = timeToPos(w.m_endTime);
        m_workTimeEnd = fabs(startPos - event->posF().x()) < fabs(endPos - event->posF().x()) ?
            TimeLineWidget::Beginning : TimeLineWidget::End;
        m_resizeFSM.mousePressed();
    }

    if (event->button() == 1 && m_resizeFSM.getState().getId() != ResizeFSM::Resizing.getId())
    {
        for (int i = 0; i < m_presenceTimes.count(); ++i)
        {
            TimeFrame& w = m_presenceTimes[i];
            qreal startPos = timeToPos(w.m_startTime);
            qreal endPos = timeToPos(w.m_endTime);

            if (startPos <= event->posF().x() &&
                event->posF().x() <= endPos &&
                (event->posF().y() <= height() - m_fontHeight))
            {
                m_highlightedPresenceTime = i;
                repaint();
                break;
            }

        }
    }
}

void TimeLineWidget::mouseReleaseEvent(QMouseEvent* /*event*/)
{
    m_resizeFSM.mouseReleased();
    if (m_highlightedWorkingTime >= 0)
    {
        emit workingTimeAdjusted(this, m_workTimes[m_highlightedWorkingTime]);
    }
}

void TimeLineWidget::savePos()
{
    m_startDragPos = QCursor::pos().x();
}

void TimeLineWidget::restorePos()
{
}

void TimeLineWidget::handleNewPos()
{
    TimeFrame& w = m_workTimes[m_highlightedWorkingTime];

    //qreal timeLineWidth = width() - m_zeroWidth;
    //return m_dayStartTime.addSecs((60 * 60 * 24) / timeLineWidth * (position - m_zeroWidth / 2));
    //int secs = (60 * 60 * 24) / timeLineWidth * (m_startDragPos - QCursor::pos().x());

    int pos = mapFromGlobal(QCursor::pos()).x();

    if (m_workTimeEnd == TimeLineWidget::End)
    {
        for (int i = 0; i < m_presenceTimes.count(); ++i)
        {
            TimeFrame& p = m_presenceTimes[i];
            //qDebug() << posToTime(pos).secsTo(p.m_endTime);
            if (abs(posToTime(pos).secsTo(p.m_endTime)) < (15 * 60))
            {
                w.m_endTime = p.m_endTime;
                break;
            }
            else
            {
                w.m_endTime = posToTime(pos);
            }
        }
    }
    else
    {
        for (int i = 0; i < m_presenceTimes.count(); ++i)
        {
            TimeFrame& p = m_presenceTimes[i];
            //qDebug() << posToTime(pos).secsTo(p.m_startTime);
            if (abs(posToTime(pos).secsTo(p.m_startTime)) < (15 * 60))
            {
                w.m_startTime = p.m_startTime;
                break;
            }
            else
            {
                w.m_startTime = posToTime(pos);
            }
        }

    }
    //repaint();
    emit workingTimeAdjusted(this, m_workTimes[m_highlightedWorkingTime]);
}


/*
void TimeLineWidget::mouseMoveEvent(QMouseEvent* event)
{
    qreal timeLineWidth = (width() - m_zeroWidth / 2.0 - QFontMetrics(m_font).width("24") / 2.0);
    qreal minuteStep = timeLineWidth / 24.0 / 60.0;

    for (int i = 0; i <  m_presences.count(); ++i)
    {
        PresenceData& presenceData = m_presences[i];
        qreal leftPos = (presenceData.m_startTime.hour() * 60 + presenceData.m_startTime.minute()) * minuteStep + m_zeroWidth / 2.0;
        qreal rightPos = (presenceData.m_startTime.hour() * 60 + presenceData.m_startTime.minute()) * minuteStep + presenceData.m_duration * minuteStep + m_zeroWidth / 2.0;
        if (fabs(event->pos().x() - leftPos) < 1.5 || m_resizingStartEventIndex == i)
        {
            if (event->buttons() == Qt::LeftButton)
            {
                m_resizingStartEventIndex = i;
                qreal newMinutes = (event->pos().x() - m_zeroWidth / 2.0) / minuteStep;

                int hours = newMinutes / 60.0;
                int minutes = newMinutes - hours * 60;
                qDebug() << hours << minutes;
                qreal movement = presenceData.m_startTime.hour() * 60 + presenceData.m_startTime.minute() - (hours * 60 + minutes);
                qreal duration = presenceData.m_duration + movement;

                presenceData.m_startTime = QTime(hours, minutes);
                presenceData.m_duration = duration;
                repaint();
            }
            else
            {
                m_resizingStartEventIndex = -1;
            }
            setCursor(Qt::SizeHorCursor);
            m_resizing = true;
            break;
        }
        else if (fabs(event->pos().x() - rightPos) < 1.5 || m_resizingEndEventIndex == i)
        {
            if (event->buttons() == Qt::LeftButton)
            {
                m_resizingEndEventIndex = i;
                presenceData.m_duration += (event->pos().x() - rightPos) / minuteStep;
                repaint();
            }
            else
            {
                m_resizingEndEventIndex = -1;
            }
            setCursor(Qt::SizeHorCursor);
            m_resizing = true;
            break;
        }
        else
        {
            setCursor(Qt::ArrowCursor);
            m_resizing = false;
        }
    }
}
void TimeLineWidget::mousePressEvent(QMouseEvent* event)
{
    if (m_resizing)
    {
        mouseMoveEvent(event);
    }
}
*/
